import {reactive, ref, Ref} from 'vue'

import {MsgUtil, ObjUtil} from '@/utils'
import {CloseModelEvent} from '@/types'


interface ConstructorParams {
    rowKey: string
    tplRecord: Record<string, any>
    rawRecord?: Record<string, any>
    emit: any
}

export class EditDrawer {
    /**
     * 单条数据的Key字段名称
     * */
    rowKeyName = 'id'

    /**
     * 绑定到表单的Ref对象
     * */
    formRef = ref(null)

    /**
     * 表单绑定对象
     * */
    formState: Ref<Record<string, any>>

    /**
     * 原始独享
     * */
    protected rawRecord: Record<string, any>

    isUpdate = false

    // 数据验证之前执行方法
    beforeSubmit: any

    // 数据验证通过之后 发送Ajax数据之前的拦截方法  此方法必须返回一个布尔值
    afterValidateHandler: any

    addRequest: any

    updateRequest: any

    emit: any


    cancelBtn = {text: '取消', disabled: false, click: null}

    LAYER = reactive({
        title: '',
        visible: true,
        width: 768,
        closable: true,
        escToClose: true,
        unmountOnClose: true,
        maskClosable: false,
        footer: true,
        okText: '确定保存',
        okLoading: false,
        cancelText: '取消',

    })

    /**
     * @desc 初始化窗口对象
     * @param rowKey 数据组件Key 一般情况都为 id
     * @param tplRecord 后端提供的DTO 对象模板
     * @param rawRecord 需要修改的原始数据
     * @param emit 定义的回调方法入口
     * */
    constructor({tplRecord, rawRecord, rowKey, emit}: ConstructorParams) {
        this.rowKeyName = rowKey
        this.emit = emit
        this.isUpdate = rawRecord?.[rowKey] !== undefined
        if (this.isUpdate) {
            this.rawRecord = rawRecord
            this.formState = ref(ObjUtil.pick(tplRecord, rawRecord))
        } else {
            // 深拷贝一次对象
            const data = JSON.parse(JSON.stringify(tplRecord))
            this.formState = ref({...data, ...rawRecord})
        }


    }

    /**
     * @desc 修改窗口宽度
     * @param title 窗口标题
     * @param width 窗口宽度数值
     * */
    setLAYER(title, width = 768) {
        if (width <= 200) {
            MsgUtil.message('窗口大小不能小于200像素')
            return
        }
        this.LAYER.width = width
        this.LAYER.title = title
        return this
    }


    /**
     * @desc 配置数据新增的执行方法
     * @param request 执行数据新增的执行方法
     * */
    setAddRequest(request) {
        this.addRequest = request
        return this
    }

    /**
     * @desc 配置数据修改的执行方法
     * @param request 执行数据修改的执行方法
     * */
    setUpdateRequest(request) {
        this.updateRequest = request
        return this
    }

    /**
     * 执行数据新增操作
     * */
    private addAction = async () => {
        if (typeof this.addRequest !== 'function') throw new Error('尚未初始化数据新增的执行方法,setAddXhr 方法进行初始化')
        const {message} = await this.addRequest(this.formState.value)
        MsgUtil.notify('操作成功!', message)
        this.onCancel('RELOAD')
    }

    /**
     * 执行数据修改操作
     * */
    private updateAction = async () => {
        if (typeof this.updateRequest !== 'function') throw new Error('尚未初始化数据修改的执行方法,updateXhr 方法进行初始化')
        const key = this.rawRecord[this.rowKeyName]
        const {message} = await this.updateRequest(key, this.formState.value)
        MsgUtil.notify('操作成功!', message)
        this.onCancel('REFRESH')
    }

    lockLayer = () => {
        this.LAYER.okLoading = true
        this.LAYER.closable = false
        this.LAYER.escToClose = false
    }

    /*
     * 解锁窗口操作
     * */
    unLockLayer = () => {
        this.LAYER.okLoading = false
        this.LAYER.closable = true
        this.LAYER.escToClose = true
    }


    /**
     * 窗口提交事件
     * */
    onSubmit = async (): Promise<boolean> => {

        if (typeof this.beforeSubmit === 'function') this.beforeSubmit()
        const err = await this.formRef.value.validate();
        if (err !== undefined) return false


        let run = true
        if (typeof this.afterValidateHandler === 'function') run = this.afterValidateHandler()
        if (!run) return false;


        try {
            this.lockLayer()
            this.isUpdate ? await this.updateAction() : await this.addAction()
            return true;
        } catch (err) {
            console.error(err)
            return false
        } finally {
            this.unLockLayer();
        }


    }

    /**
     * 窗口事件
     * */
    onCancel = (eventCode: CloseModelEvent = 'NONE') => {
        this.formState.value = {}
        this.emit('cancel', eventCode)
    }


    public readCtrHandler: any



    /**
     * 只读弹窗
     * */
    public readCtr = reactive({
        show: false,
        record: {},
        open: (e: Record<string, any> = {}) => {
            this.readCtr.show = true
            this.readCtr.record = e
        },
        close: async (e) => {
            this.readCtrHandler(e);
            this.readCtr.show = false
            this.readCtr.record = {}

        },
    })

}
